const http = require('http');
const fs = require('fs');

// .jpg  .jpeg  --->  image/jpeg
//.png  --->  image/png
//.gig --->  image/gif
//.ico  --->  image/x-ico
//.txt --->  text/plain
//.json  --->  text/json或application/json
//.xml ---> text/xml或application/xml

// ------------------解析Body数据------------------------

/**
 * Content-Disposition:form-data;name = "file" ; filename = "xxx"
 * @param {string} headerData
 */

function parseBodyHeaders(headerData){
    //.filter   创建一个数组  参数是测试每个元素函数，为true则通过
    let hlist = headerData.split('\r\n').filter(p => p.length > 0);

    //解析content-disposititon => hlist[0]
    //按照;切分数组，选出第二个元素开始数组
    let csplit = hlist[0].split(';').slice(1)

    let filename
    let name
    for(let a of csplit){
        if(a.indexOf('filename=') === 0){
            filename = a.substring(a.indexOf('=') + 2,a.length - 1)
        }else{
            name = a.substring(a.indexOf('=') + 2,a.length - 1)
        }
    }

    let headers = {}
    let ind = 0;
    let k

    //for...in 循环：只能获得对象的键名，不能获得键值
    //for...of 循环：允许遍历获得键值
    //例如遍历数组arr，
    //for item in arr:item只能得到0,1,2的索引，
    //for item of arr:能得到对应的内容
    for(let h of hlist){
        //1、indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
        //第二个参数（非必须）代表可选的整数参数。规定在字符串中开始检索的位置
        //2、substring() 方法用于提取字符串中介于两个指定下标之间的字符,
        //如果省略第二个参数，如果省略该参数，那么返回的子串会一直到字符串的结尾。
        //3、trim() 去除字符串的头尾空格
        ind = h.indexOf(':')
        k = h.substring(0,ind).toLowerCase()
        headers[k] = h.substring(ind+1).trim()
    }

    return {
        filename,
        name,
        headers,
        contentType:headers['content-type'] || ''
    }
}


function parseBody(bodyData,headers){
    let ctype = headers['content-type']
    let bdy = ctype.substring(ctype.indexOf('=') + 1);
    let crlf_bdy = `\r\n--${bdy}`
    let header_end_index = bodyData.indexOf('\r\n\r\n',crlf_bdy.length)
    let headerData = bodyData.toString('utf8',crlf_bdy.length,header_end_index);


    //解析文件头信息
    let hd = parseBodyHeaders(headerData)

    let file = {
        start:header_end_index + 4,
        end:bodyData.indexOf(crlf_bdy,header_end_index),
        ...hd
    }

    file.length = file.end - file.start

    return file

}

//-------------------解析Body数据 - END-----------------------



let html = `
<!DOCTYPE html>
<html>
    <head>
        <title>First HTTP</title>
    </head>
    <body>
        你好
    </body>
</html>
`
let routerTable = {

    GET:{
        '/':async(req,res) => {
            res.setHeader('content-type','text/html; charset=utf-8'); 
            res.end(html);
        },
        '/test':async(req,res) => {
            let status = parseInt(Math.random() * 200) + 199;
            //statusCode代表状态码
            res.statusCode = status;
            res.end('test end');
        },
        '/upload':async(req,res) => {
            //createReadStream()
            // 第一个参数，读取文件的路径
            //第二个参数 highWaterMark 最高水位线,默认最多读取64K
            let stm = fs.createReadStream('./upload.html');
            stm.pipe(res,{end:false});
            stm.on('end',() => {
                res.end()
            })
        }
    
    },

    POST:{
        '/data':async(req,res) => {
            let bufferList = [];
            let bufferLength = 0;
            req.on('data',chunk => {
                bufferLength += chunk.length;
                bufferList.push(chunk);
            })

            let bodyData = null;
            req.on('end',() => {
                if(bufferList.length > 0){
                //Buffer.concat()方法用于将给定数组中的所有缓冲区对象合并为一个缓冲区对象
                bodyData = Buffer.concat(bufferList,bufferLength);
                bufferList = [];
                }

                let file = parseBody(bodyData,req.headers)
                console.log(file)

                if(bodyData){
                    res.end(bodyData);
                }else{
                    res.end()
                }
            })
        },
    }
      

}

http.createServer((req,res) => {

    let rm = routerTable[req.method]
    if(!rm || !rm[req.url]){
        res.statusCode= 404;
        res.end('page not found');
        return
    }

    rm[req.url](req,res);
    
}).listen(3456)



